/**
 * 主文件
 */

package main

import (
    "gitee.com/mayiweb/gohs"
    "gitee.com/mayiweb/gohs/safe"
    "os"
    "time"
)

var (
    // ctp 句柄及配置项
    Ctp HsClient

    // 行情模块函数 句柄
    MdSpi HsMdSpi

    // ctp 队列 句柄
    Queue *CtpQueue

    // 交易模块函数 句柄
    // TradeSpi *gohs.NewDirectorCMyTradeSpi
    TradeSpi HsTradeSpi

    // 交易所合约详情列表 InstrumentStruct
    MapInstruments safe.Map

    // 资金账户信息 AccountStruct
    MapAccount safe.Map

    // 报单列表（未成交的）OrderStruct
    MapOrders safe.Map

    // 报单成交列表
    MapTrades safe.Map

    // 持仓列表 PositionStruct
    MapPositions safe.Map

    // 行情 RequestId 对应的 订阅、退订 合约数据
    MapMdRequests safe.Map

    // 报单 OrderRef 事件
    MapOrderRefAction safe.Map

    // 报单有效期任务
    MapOrderTask safe.Map

    // 订单申报（每秒最多5笔）
    MapOrderDeclare safe.Map

    // 交易、行情 服务器
    MdFront []string
    TradeFront []string

    // 交易账号
    BrokerID string
    AccountID string
    Password string

    // 客户端认证
    AppID string
    AuthCode string

    // 证书
    LicensePath string
    MdLicensePath string

    // sdk 成功返回值
    SDK_OK int = 0

    // ctp 流文件，绝对路径
    StreamFile string = GetCurrentDirectory() + "/StreamFile/"

    // 买卖方向：买
    OrderBuy byte  = '1'

    // 买卖方向：卖
    OrderSell byte = '2'

    // 运行模式（prod 生产，test 标准环境测试，dev 24小时测试）
    RunMode string
)

// 获得交易账号
func SetTradeAccount() {

    switch RunMode {

        // 生产环境
        case "prod":
            MdFront       = []string{}
            TradeFront    = []string{}
            AccountID     = ""
            Password      = ""
            AppID         = ""
            AuthCode      = ""
            LicensePath   = ""
            MdLicensePath = ""

        // 测试账号
        case "test":
            MdFront       = []string{}
            TradeFront    = []string{}
            AccountID     = ""
            Password      = ""
            AppID         = ""
            AuthCode      = ""
            LicensePath   = ""
            MdLicensePath = ""

        // 恒生期货
        case "qh":
            MdFront       = []string{}
            TradeFront    = []string{}
            AccountID     = ""
            Password      = ""
            AppID         = ""
            AuthCode      = ""
            LicensePath   = ""
            MdLicensePath = ""

        default:
            LogPrintln("该模式未配置交易信息，程序退出。")
            os.Exit(0)
    }
}

// 初始化，在 main 之前执行
func init() {

    // 全局 行情、交易 函数句柄
    MdSpi    = HsMdSpi{}
    TradeSpi = HsTradeSpi{}

    // 全局队列句柄
    Queue = &CtpQueue{}

    // 检查流文件目录是否存在
    fileExists, _ := PathExists(StreamFile)
    if !fileExists {
        err := os.Mkdir(StreamFile, os.ModePerm)
        if err != nil {
           LogPrintln("创建目录失败，请检查是否有操作权限")
        }
    }

    // 运行模式【运行程序时带上参数可设置】
    if len(os.Args) < 2 {
        RunMode = "test"
    } else {
        RunMode = os.Args[1]
    }

    // 启动队列查询任务
    go RunQueryTask()

    // 启动报单有效期任务
    go RunOrderInsertTask()
}

// 主程序入口
func main() {

    defer CheckPanic()

    LogPrintln("启动交易程序")

    // 设置交易账号
    SetTradeAccount()

    // 交易请求号（由 月日 组成）【int 最大值 2147483647，月份最大12月，最大长度为10位】
    RequestId := StringToInt(time.Now().Format("0102")) * 100000

    Ctp = HsClient {
        MdApi: gohs.NewMdApi(StreamFile),
        TradeApi: gohs.NewTradeApi(StreamFile),
        MdFront: MdFront,
        TradeFront: TradeFront,
        AccountID: AccountID,
        Password: Password,
        AppID: AppID,
        AuthCode: AuthCode,
        LicensePath: LicensePath,
        MdLicensePath: MdLicensePath,
        MdRequestId: RequestId,
        TradeRequestId: RequestId,
        IsTradeInit: false,
        IsTradeLogin: false,
        IsTradeInitFinish: false,
        IsMdInit: false,
        IsMdLogin: false,
    }

    // 如果没有行情授权文件则使用交易的授权文件
    if Ctp.MdLicensePath == "" {
        Ctp.MdLicensePath = Ctp.LicensePath
    }

    // 设置 API结构体版本校验、通讯证书
    HSMdInitConfig := gohs.NewCHSInitConfigField()
    HSMdInitConfig.SetAPICheckVersion(SetSwigInt32(int32(gohs.API_STRUCT_CHECK_VERSION)))
    HSMdInitConfig.SetCommLicense(Ctp.MdLicensePath)


    // 行情系统注册
    Ctp.MdApi.RegisterSpi(gohs.NewDirectorCHSMdSpi(&HsMdSpi{Ctp}))

    for _, val := range Ctp.MdFront {
        Ctp.MdApi.RegisterFront(val)
    }

    // 行情 API 初始化，连接UFT系统时传入许可证路径
    iMdResult := Ctp.MdApi.Init(HSMdInitConfig)
    if iMdResult != SDK_OK {
        LogPrintln(MdSpi.GetApiErrorMsg(iMdResult))
    }


    // 交易系统注册
    Ctp.TradeApi.RegisterSpi(gohs.NewDirectorCHSTradeSpi(&HsTradeSpi{Ctp}))

    for _, val := range Ctp.TradeFront {
        Ctp.TradeApi.RegisterFront(val)
    }

    // 设置 API结构体版本校验、通讯证书
    HSTradeInitConfig := HSMdInitConfig
    HSTradeInitConfig.SetCommLicense(Ctp.LicensePath)

    // 交易 API 初始化，连接UFT系统时传入许可证路径
    iTradeResult := Ctp.TradeApi.Init(HSTradeInitConfig)
    if iTradeResult != SDK_OK {
        LogPrintln(TradeSpi.GetApiErrorMsg(iTradeResult))
    }

    Ctp.TradeApi.Join()
    Ctp.MdApi.Join()

    // .Join() 如果后面有其它需要处理的功能可以不写，但必须保证程序不能退出，Join 就是保证程序不退出的
}